import sys
import cv2
import numpy as np
import json
import os
import datetime
import time
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QFrame, QRadioButton,
                             QPushButton, QVBoxLayout, QHBoxLayout, QGroupBox,
                             QStatusBar, QLineEdit, QFormLayout, QSlider, QTabWidget,
                             QCheckBox, QGridLayout, QTextEdit, QFileDialog, QButtonGroup, QComboBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QMutex, QMutexLocker
from PyQt5.QtGui import QImage, QPixmap, QColor, QPalette, QFont, QIntValidator
import mediapipe as mp
import requests
from requests.auth import HTTPDigestAuth
import pygame  # 添加pygame用于播放音频
from pygame import mixer
import socket


# 添加模型路径设置
if getattr(sys, 'frozen', False):
    base_path = sys._MEIPASS
else:
    base_path = os.path.dirname(os.path.abspath(__file__))

model_path = os.path.join(base_path, 'mediapipe_models')
os.environ['MEDIAPIPE_MODEL_BASE_DIR'] = model_path


# 初始化MediaPipe
mp_hands = mp.solutions.hands
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils

class ImageLabel(QLabel):
    """支持鼠标点击获取坐标的自定义标签"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAlignment(Qt.AlignCenter)
        self.setMouseTracking(True)

class VideoThread(QThread):
    """视频捕获线程"""
    frame_signal = pyqtSignal(np.ndarray)
    status_signal = pyqtSignal(str)
    
    def __init__(self, rtsp_url, width=1280, height=720, fps=15):
        super().__init__()
        self.rtsp_url = rtsp_url
        self.running = False
        self.cap = None
        self.target_width = width
        self.target_height = height
        self.target_fps = fps
        self.reconnect_attempts = 0
        self.max_reconnect_attempts = 5
    
    def run(self):
        self.running = True
        self.status_signal.emit("正在连接摄像头...")
        
        try:
            if not self.connect_camera():
                return
                
            actual_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            actual_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            actual_fps = self.cap.get(cv2.CAP_PROP_FPS)
            self.status_signal.emit(f"连接成功，分辨率: {actual_width}x{actual_height}, 帧率: {actual_fps:.1f}fps")
            
            while self.running:
                ret, frame = self.cap.read()
                if not ret:
                    self.status_signal.emit("读取帧失败，尝试重新连接...")
                    if not self.reconnect():
                        self.status_signal.emit("重新连接失败，停止视频捕获")
                        break
                    continue
                
                # 直接发送原始帧，避免复制
                self.frame_signal.emit(frame)
                
        except Exception as e:
            self.status_signal.emit(f"视频捕获错误: {str(e)}")
        finally:
            if self.cap:
                self.cap.release()
            self.status_signal.emit("视频捕获已停止")
    
    def connect_camera(self):
        """连接摄像头"""
        try:
            self.cap = cv2.VideoCapture(self.rtsp_url, cv2.CAP_FFMPEG)
            self.cap.set(cv2.CAP_PROP_OPEN_TIMEOUT_MSEC, 10000)
            
            # 设置分辨率和帧率
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.target_width)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.target_height)
            self.cap.set(cv2.CAP_PROP_FPS, self.target_fps)
            
            try:
                self.cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY)
            except:
                pass
            self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
            
            if not self.cap.isOpened():
                self.status_signal.emit("无法打开RTSP流")
                return False
            return True
        except:
            return False
    
    def reconnect(self):
        """重新连接摄像头"""
        if self.reconnect_attempts >= self.max_reconnect_attempts:
            return False
            
        if self.cap:
            self.cap.release()
            
        self.status_signal.emit("正在尝试重新连接...")
        self.reconnect_attempts += 1
        
        if self.connect_camera():
            self.reconnect_attempts = 0
            actual_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            actual_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            self.status_signal.emit(f"重新连接成功，分辨率: {actual_width}x{actual_height}")
            return True
        return False
    
    def stop(self):
        self.running = False
        self.wait(2000)

class DetectionThread(QThread):
    """AI检测处理线程 - 优化版本"""
    result_signal = pyqtSignal(np.ndarray, np.ndarray, bool, bool, dict, dict, int, bool, float)
    debug_signal = pyqtSignal(str)  # 新增调试信号
    
    def __init__(self, detector):
        super().__init__()
        self.detector = detector
        self.running = False
        self.mutex = QMutex()
        self.latest_frame = None
        self.has_new_frame = False
    
    def add_frame(self, frame):
        """更新最新帧"""
        with QMutexLocker(self.mutex):
            self.latest_frame = frame
            self.has_new_frame = True
    
    def run(self):
        self.running = True
        while self.running:
            frame = None
            # 获取最新帧
            with QMutexLocker(self.mutex):
                if self.has_new_frame:
                    frame = self.latest_frame
                    self.has_new_frame = False
            
            if frame is None:
                self.msleep(100)  # 增加休眠时间减少CPU占用
                continue
                
            try:
                # 处理帧
                raw_frame, processed_frame, left_detected, right_detected, left_info, right_info, person_detected, person_confidence = self.detector.process_frame(frame)
                self.result_signal.emit(
                    raw_frame, processed_frame, left_detected, right_detected, 
                    left_info, right_info, self.detector.missed_detections, 
                    person_detected, person_confidence
                )
            except Exception as e:
                print(f"检测处理错误: {str(e)}")
                self.debug_signal.emit(f"检测处理错误: {str(e)}")
    
    def stop(self):
        self.running = False
        self.wait(1000)

class GloveDetector:
    def __init__(self):
        # 默认参数
        self.params = {
            "global_point_interval": 5,
            "detection_interval": 500,
            "hand_confidence_threshold": 0.5,
            "h_min": 0,
            "h_max": 180,
            "s_min": 0,
            "s_max": 255,
            "v_min": 0,
            "v_max": 255,
            "color_tolerance": 30,
            "point_threshold": 20,
            "ratio_threshold": 0.5,
            "max_missed_detections": 5,
            "pause_recognition": False,
            "wrist_radius": 30  # 新增手腕半径参数
        }
        
        self.debug_mode = False
        self.force_detection = False
        self.force_show_points = False
        
        self.left_glove_detected = False
        self.right_glove_detected = False
        self.missed_detections = 0
        self.last_detection_time = 0
        self.no_person_count = 0  # 用于记录连续未检测到人的次数
        self.person_detected = False  # 新增：检测是否有人在画面中
        self.person_confidence = 0.0  # 新增：人员检测置信度
        
        self.original_frame = None
        self.processed_frame = None
        self.overlay_frame = None
        
        self.hands = None
        self.pose = None
        
        # 加载参数
        self.params_file = "glove_params.json"
        self.load_parameters()
        
        # 应用参数
        self.__dict__.update(self.params)
        
        # 初始化模型
        self.initialize_models()
        
        # 检测帧率控制
        self.last_detection_time = 0
        
        # 手动录制状态
        self.manual_recording = False
        self.manual_video_writer = None
        
        # 报警状态
        self.alarm_active = False
        self.alarm_start_time = None
        self.alarm_duration = 1.0
        
        # 优化: 预分配HSV掩码
        self.hsv_mask = None

        # 新增报警音频播放状态
        self.alarm_sound_playing = False
    
    def initialize_models(self):
        """初始化MediaPipe模型"""
        try:
            # 手部模型
            self.hands = mp_hands.Hands(
                static_image_mode=False,
                max_num_hands=2,
                min_detection_confidence=0.6,
                min_tracking_confidence=0.5,
                model_complexity=1)
            
            # 姿势模型
            self.pose = mp_pose.Pose(
                static_image_mode=False,
                min_detection_confidence=0.6,
                model_complexity=1)
        except Exception as e:
            print(f"模型初始化错误: {str(e)}")
    
    def load_parameters(self):
        try:
            if os.path.exists(self.params_file):
                with open(self.params_file, 'r') as f:
                    self.params.update(json.load(f))
        except Exception as e:
            print(f"加载参数错误: {str(e)}")
    
    def save_parameters(self):
        try:
            with open(self.params_file, 'w') as f:
                json.dump(self.params, f, indent=4)
            return True
        except Exception as e:
            print(f"保存参数错误: {str(e)}")
            return False
    
    def process_frame(self, frame):
        if frame is None or frame.size == 0:
            return None, None, False, False, {}, {}, False, 0.0
            
        # 创建用于显示的原始帧副本
        if self.debug_mode or self.force_show_points:
            display_frame = frame.copy()
            self.draw_global_glove_points(display_frame)
            self.force_show_points = False
        else:
            display_frame = frame
            
        if self.pause_recognition and not self.force_detection:
            return display_frame, frame, self.left_glove_detected, self.right_glove_detected, {}, {}, self.person_detected, self.person_confidence
            
        current_time = time.time() * 1000
        
        # 修改报警逻辑：只有检测到人在画面中时才报警
        if not self.left_glove_detected or not self.right_glove_detected:
            # 只有当人在画面中时才增加未检测计数
            if self.person_detected:
                self.missed_detections += 1
                if self.missed_detections >= self.max_missed_detections and not self.alarm_active:
                    self.alarm_active = True
                    self.alarm_start_time = datetime.datetime.now()
                    self.save_alarm_image(frame)
                    # 播放报警声音
                    self.play_alarm_sound()
                # 重置不在画面计数器
                self.no_person_count = 0
            else:
                # 如果人不在画面中，增加不在画面计数器
                self.no_person_count += 1
                # 当连续不在画面次数达到阈值时，解除报警
                if self.no_person_count >= self.max_missed_detections:
                    self.missed_detections = 0
                    if self.alarm_active:
                        self.alarm_active = False
                        self.stop_alarm_sound()
        else:
            self.missed_detections = 0
            self.no_person_count = 0
            if self.alarm_active:
                self.alarm_active = False
                self.stop_alarm_sound()

        # 仅在需要时进行检测
        if self.force_detection or self.last_detection_time == 0 or current_time - self.last_detection_time >= self.detection_interval:
            self.last_detection_time = current_time
            self.force_detection = False
            
            # 使用原始帧避免复制
            self.original_frame = frame
            self.processed_frame = frame
            self.overlay_frame = frame.copy()
            
            self.detect_hands_and_pose()
            
            left_info = {}
            right_info = {}
            
            # 混合模型检测逻辑
            hands_left, hands_right, hands_left_info, hands_right_info = self.draw_hands_model()
            
            # 如果手部模型检测到两只手，直接使用结果
            if hands_left is not None and hands_right is not None:
                self.left_glove_detected, self.right_glove_detected = hands_left, hands_right
                left_info, right_info = hands_left_info, hands_right_info
            # 如果只检测到一只手或没有手，切换到姿势模型
            else:
                pose_left, pose_right, pose_left_info, pose_right_info = self.draw_pose_model()
                
                # 确保检测结果正确传递
                if hands_left is not None:
                    self.left_glove_detected = hands_left
                elif pose_left is not None:
                    self.left_glove_detected = pose_left
                
                if hands_right is not None:
                    self.right_glove_detected = hands_right
                elif pose_right is not None:
                    self.right_glove_detected = pose_right
                
                # 确保信息正确传递
                if hands_left_info:
                    left_info = hands_left_info
                elif pose_left_info:
                    left_info = pose_left_info
                    
                if hands_right_info:
                    right_info = hands_right_info
                elif pose_right_info:
                    right_info = pose_right_info
            
            return display_frame, self.overlay_frame, self.left_glove_detected, self.right_glove_detected, left_info, right_info, self.person_detected, self.person_confidence
        else:
            processed_frame = self.overlay_frame if self.overlay_frame is not None else frame
            return display_frame, processed_frame, self.left_glove_detected, self.right_glove_detected, {}, {}, self.person_detected, self.person_confidence

    def detect_hands_and_pose(self):
        if self.original_frame is None or self.original_frame.size == 0:
            self.person_detected = False
            self.person_confidence = 0.0
            return
            
        # 缩小图像以提高处理速度
        small_frame = cv2.resize(self.original_frame, (0, 0), fx=0.25, fy=0.25)
        rgb_frame = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB)
        
        # 同时使用手部和姿态检测判断人员存在
        hands_results = self.hands.process(rgb_frame)
        pose_results = self.pose.process(rgb_frame)
        
        # 计算综合置信度
        hand_confidence = 0.0
        pose_confidence = 0.0
        
        # 手部检测置信度
        if hands_results.multi_hand_landmarks:
            for hand_landmarks in hands_results.multi_hand_landmarks:
                # 取所有关键点可见度的平均值
                visibilities = [landmark.visibility for landmark in hand_landmarks.landmark]
                hand_confidence = max(hand_confidence, sum(visibilities) / len(visibilities))
        
        # 姿态检测置信度
        if pose_results.pose_landmarks:
            # 取上半身关键点（肩膀、肘部、手腕）的可见度平均值
            upper_body_indices = [
                mp_pose.PoseLandmark.LEFT_SHOULDER,
                mp_pose.PoseLandmark.RIGHT_SHOULDER,
                mp_pose.PoseLandmark.LEFT_ELBOW,
                mp_pose.PoseLandmark.RIGHT_ELBOW,
                mp_pose.PoseLandmark.LEFT_WRIST,
                mp_pose.PoseLandmark.RIGHT_WRIST
            ]
            
            visibilities = []
            for landmark_idx in upper_body_indices:
                landmark = pose_results.pose_landmarks.landmark[landmark_idx.value]
                visibilities.append(landmark.visibility)
            
            if visibilities:
                pose_confidence = sum(visibilities) / len(visibilities)
        
        # 综合置信度取两者最大值
        self.person_confidence = max(hand_confidence, pose_confidence)
        
        # 检测是否有人（通过手部或姿态检测）
        self.person_detected = (
            (hands_results is not None and hands_results.multi_hand_landmarks is not None) or
            (pose_results is not None and pose_results.pose_landmarks is not None)
        )
        
        # 保存结果用于后续处理
        self.hands_results = hands_results
        self.pose_results = pose_results

    def play_alarm_sound(self):
        """播放报警声音"""
        if not self.alarm_sound_playing:
            try:
                # 加载并播放报警声音
                mixer.music.load("alarm_sound.wav")  # 确保有alarm_sound.wav文件
                mixer.music.play(-1)  # -1表示循环播放
                self.alarm_sound_playing = True
            except Exception as e:
                print(f"播放报警声音失败: {str(e)}")
    
    def stop_alarm_sound(self):
        """停止报警声音"""
        if self.alarm_sound_playing:
            try:
                mixer.music.stop()
                self.alarm_sound_playing = False
            except Exception as e:
                print(f"停止报警声音失败: {str(e)}")
                
    def save_alarm_image(self, frame):
        """保存报警时的原始帧图片"""
        try:
            # 创建alarm_images目录
            if not os.path.exists("alarm_images"):
                os.makedirs("alarm_images")
                
            timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = os.path.join("alarm_images", f"glove_alarm_{timestamp}.jpg")
            cv2.imwrite(filename, frame)
            print(f"报警图片已保存: {filename}")
        except Exception as e:
            print(f"保存报警图片失败: {str(e)}")

    def get_hsv_bounds(self):
        """计算HSV边界范围，避免重复代码"""
        return (
            np.array([
                max(0, self.h_min - self.color_tolerance),
                max(0, self.s_min - self.color_tolerance),
                max(0, self.v_min - self.color_tolerance)
            ]),
            np.array([
                min(180, self.h_max + self.color_tolerance),
                min(255, self.s_max + self.color_tolerance),
                min(255, self.v_max + self.color_tolerance)
            ])
        )
    
    def draw_global_glove_points(self, frame):
        """在整个帧上绘制符合HSV阈值的点"""
        hsv_image = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        lower_bound, upper_bound = self.get_hsv_bounds()
        
        # 创建掩码
        hsv_mask = cv2.inRange(hsv_image, lower_bound, upper_bound)
        
        # 在帧上标记白手套点
        y_indices, x_indices = np.where(hsv_mask > 0)
        for i in range(0, len(x_indices), self.global_point_interval):
            x = x_indices[i]
            y = y_indices[i]
            cv2.circle(frame, (x, y), 1, (0, 255, 0), -1)
    
    def draw_hands_model(self):
        left_glove_detected = None
        right_glove_detected = None
        left_info = {}
        right_info = {}
        
        if self.hands_results is None or self.hands_results.multi_hand_landmarks is None:
            return left_glove_detected, right_glove_detected, left_info, right_info
        
        h, w, _ = self.original_frame.shape
        
        for hand_landmarks, handedness in zip(self.hands_results.multi_hand_landmarks, self.hands_results.multi_handedness):
            mp_drawing.draw_landmarks(
                self.overlay_frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing.DrawingSpec(color=(255, 0, 0)), 
                mp_drawing.DrawingSpec(color=(0, 0, 255)))
            
            hand_type = handedness.classification[0].label
            mask = np.zeros((h, w), dtype=np.uint8)
            points = []
            
            for landmark in hand_landmarks.landmark:
                visibility = 1.0 - (landmark.z if landmark.z > 0 else 0)
                if visibility > self.hand_confidence_threshold:
                    # 坐标需要放大2倍，因为我们缩小了图像
                    x = min(max(int(landmark.x * w), 0), w-1)
                    y = min(max(int(landmark.y * h), 0), h-1)
                    points.append([x, y])
            
            if len(points) < 5:
                continue
            
            points = np.array(points)
            hull = cv2.convexHull(points)
            cv2.fillConvexPoly(mask, hull, 255)
            
            glove_detected, glove_points, normalized_points = self.detect_glove_in_region(mask, hand_type, "hands")
            
            if hand_type == "Left":
                left_glove_detected = glove_detected
                left_info = {
                    'points': glove_points,
                    'ratio': normalized_points,
                    'method': 'hands'
                }
            else:
                right_glove_detected = glove_detected
                right_info = {
                    'points': glove_points,
                    'ratio': normalized_points,
                    'method': 'hands'
                }
                
        return left_glove_detected, right_glove_detected, left_info, right_info

    def draw_pose_model(self):
        left_glove_detected = None
        right_glove_detected = None
        left_info = {}
        right_info = {}
        
        if self.pose_results is None or self.pose_results.pose_landmarks is None:
            return left_glove_detected, right_glove_detected, left_info, right_info
        
        h, w, _ = self.original_frame.shape
        
        mp_drawing.draw_landmarks(
            self.overlay_frame,
            self.pose_results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS,
            landmark_drawing_spec=mp_drawing.DrawingSpec(color=(0, 255, 0)), 
            connection_drawing_spec=mp_drawing.DrawingSpec(color=(0, 255, 255)))
        
        # 获取左右手腕位置
        left_wrist_idx = mp_pose.PoseLandmark.LEFT_WRIST.value
        right_wrist_idx = mp_pose.PoseLandmark.RIGHT_WRIST.value
        
        # 检测左手
        if self.pose_results.pose_landmarks.landmark[left_wrist_idx].visibility > self.hand_confidence_threshold:
            wrist_landmark = self.pose_results.pose_landmarks.landmark[left_wrist_idx]
            wrist_x = int(wrist_landmark.x * w)
            wrist_y = int(wrist_landmark.y * h)
            
            mask = np.zeros((h, w), dtype=np.uint8)
            cv2.circle(mask, (wrist_x, wrist_y), self.wrist_radius, 255, -1)
            
            glove_detected, glove_points, normalized_points = self.detect_glove_in_region(mask, "Left", "pose")
            color = (0, 255, 0) if glove_detected else (0, 0, 255)
            cv2.circle(self.overlay_frame, (wrist_x, wrist_y), 15, color, 3)
            
            left_glove_detected = glove_detected
            left_info = {
                'points': glove_points,
                'ratio': normalized_points,
                'method': 'pose'
            }
        
        # 检测右手
        if self.pose_results.pose_landmarks.landmark[right_wrist_idx].visibility > self.hand_confidence_threshold:
            wrist_landmark = self.pose_results.pose_landmarks.landmark[right_wrist_idx]
            wrist_x = int(wrist_landmark.x * w)
            wrist_y = int(wrist_landmark.y * h)
            
            mask = np.zeros((h, w), dtype=np.uint8)
            cv2.circle(mask, (wrist_x, wrist_y), self.wrist_radius, 255, -1)
            
            glove_detected, glove_points, normalized_points = self.detect_glove_in_region(mask, "Right", "pose")
            color = (0, 255, 0) if glove_detected else (0, 0, 255)
            cv2.circle(self.overlay_frame, (wrist_x, wrist_y), 15, color, 3)
            
            right_glove_detected = glove_detected
            right_info = {
                'points': glove_points,
                'ratio': normalized_points,
                'method': 'pose'
            }
                
        return left_glove_detected, right_glove_detected, left_info, right_info

    def detect_glove_in_region(self, mask, hand_type, method="hands"):
        # 获取区域内图像
        region_image = cv2.bitwise_and(self.original_frame, self.original_frame, mask=mask)
        hsv_image = cv2.cvtColor(region_image, cv2.COLOR_BGR2HSV)
        lower_bound, upper_bound = self.get_hsv_bounds()
        
        color_mask = cv2.inRange(hsv_image, lower_bound, upper_bound)
        glove_points_in_region = cv2.countNonZero(color_mask)
        
        region_area = cv2.countNonZero(mask)
        if region_area == 0:  # 避免除零错误
            return False, 0, 0.0
            
        normalized_points = glove_points_in_region / region_area
        
        # 判断是否戴手套
        glove_detected = (glove_points_in_region >= self.point_threshold and 
                         normalized_points >= self.ratio_threshold)
        
        # 绘制轮廓
        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contour_color = (0, 255, 0) if glove_detected else (0, 0, 255)
        method_color = (200, 0, 255) if method == "hands" else (255, 200, 0)
        
        for contour in contours:
            if cv2.contourArea(contour) > 100:
                cv2.drawContours(self.overlay_frame, [contour], -1, contour_color, 10)
                cv2.drawContours(self.overlay_frame, [contour], -1, method_color, 3)
        
        # 在区域内标记白手套点
        y_indices, x_indices = np.where(color_mask > 0)
        for i in range(0, len(x_indices), 5):
            x = x_indices[i]
            y = y_indices[i]
            cv2.circle(self.overlay_frame, (x, y), 1, (0, 255, 0), -1)
        
        return glove_detected, glove_points_in_region, normalized_points
    
    def start_manual_recording(self):
        if not self.manual_recording:
            self.manual_recording = True
            self.manual_record_start_time = datetime.datetime.now()
            timestamp = self.manual_record_start_time.strftime("%Y%m%d_%H%M%S")
            
            # 创建recordings目录
            if not os.path.exists("recordings"):
                os.makedirs("recordings")
                
            filename = os.path.join("recordings", f"manual_record_{timestamp}.mp4")
            
            # 确保有帧可以获取尺寸
            if hasattr(self, 'original_frame') and self.original_frame is not None:
                h, w = self.original_frame.shape[:2]
            else:
                h, w = 720, 1280  # 默认尺寸
                
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            self.manual_video_writer = cv2.VideoWriter(filename, fourcc, 15.0, (w, h))
            if not self.manual_video_writer.isOpened():
                print(f"无法打开视频文件: {filename}")
                self.manual_video_writer = None
                self.manual_recording = False
                return False
            return True
        return False
        
    def stop_manual_recording(self):
        if self.manual_recording:
            self.manual_recording = False
            if self.manual_video_writer:
                self.manual_video_writer.release()
                self.manual_video_writer = None
                return True
        return False
    
    def record_frame(self, frame):
        if frame is None or frame.size == 0:
            return
            
        if self.manual_recording and self.manual_video_writer:
            self.manual_video_writer.write(frame)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("宇视UNV摄像头控制与白手套检测系统 V1.0.0.1")
        self.setGeometry(100, 100, 1400, 800)
        
        self.video_thread = None
        self.detection_thread = None
        self.glove_detector = GloveDetector()
        self.current_frame = None
        self.paused_frame = None
        self.debug_mode = False
        self.video_paused = False
        
        # 视频设置默认值
        self.video_width = 1280
        self.video_height = 720
        self.video_fps = 15
        
        self.ptz_timers = {
            'zoom_in': QTimer(),
            'zoom_out': QTimer(),
            'focus_in': QTimer(),
            'focus_out': QTimer()
        }
        
        self.init_ui()
        self.set_dark_theme()
        
        for action in self.ptz_timers:
            self.ptz_timers[action].timeout.connect(lambda a=action: self.send_continuous_ptz(a))
            self.ptz_timers[action].setInterval(100)
        
        self.alarm_timer = QTimer()
        self.alarm_timer.timeout.connect(self.update_alarm)
        self.alarm_timer.start(200)
        self.max_alarm_duration = 30  # 最大报警持续时间（秒）

        # 加载摄像头设置
        self.load_camera_settings()
    
    def init_ui(self):
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        main_layout = QHBoxLayout(central_widget)
        
        # 左侧视频区域
        self.video_frame = QFrame()
        self.video_frame.setFrameShape(QFrame.StyledPanel)
        video_layout = QVBoxLayout(self.video_frame)
        
        video_display_layout = QHBoxLayout()
        self.raw_video_label = ImageLabel()
        self.raw_video_label.setObjectName("raw_video_label")
        self.raw_video_label.setAlignment(Qt.AlignCenter)
        self.raw_video_label.setMinimumSize(300, 200)
        self.raw_video_label.setStyleSheet("background-color: #1e1e1e; border: 1px solid #444;")
        video_display_layout.addWidget(self.raw_video_label, 40)

        # 右侧面板
        right_panel = QVBoxLayout()
        self.last_detection_label = QLabel("检测结果")
        self.last_detection_label.setAlignment(Qt.AlignCenter)
        self.last_detection_label.setStyleSheet("font-size: 14px; color: #aaa; margin-bottom: 5px;")

        self.last_detection_frame = QLabel()
        self.last_detection_frame.setAlignment(Qt.AlignCenter)
        self.last_detection_frame.setMinimumSize(600, 400)
        self.last_detection_frame.setStyleSheet("background-color: #1e1e1e; border: 1px solid #444;")
        self.last_detection_frame.setScaledContents(True)

        # 手套检测状态
        self.glove_status_frame = QFrame()
        glove_status_layout = QGridLayout(self.glove_status_frame)
        
        self.left_hand_label = QLabel("左手状态:")
        self.left_hand_label.setStyleSheet("font-size: 14px;")
        glove_status_layout.addWidget(self.left_hand_label, 0, 0)
        
        self.left_hand_result = QLabel("检测中...")
        self.left_hand_result.setStyleSheet("font-size: 16px; font-weight: bold;")
        glove_status_layout.addWidget(self.left_hand_result, 0, 1)
        
        self.left_hand_info = QLabel("")
        self.left_hand_info.setStyleSheet("font-size: 12px; color: #aaa;")
        glove_status_layout.addWidget(self.left_hand_info, 0, 2, 1, 2)  # 跨两列
        
        self.right_hand_label = QLabel("右手状态:")
        self.right_hand_label.setStyleSheet("font-size: 14px;")
        glove_status_layout.addWidget(self.right_hand_label, 1, 0)
        
        self.right_hand_result = QLabel("检测中...")
        self.right_hand_result.setStyleSheet("font-size: 16px; font-weight: bold;")
        glove_status_layout.addWidget(self.right_hand_result, 1, 1)
        
        self.right_hand_info = QLabel("")
        self.right_hand_info.setStyleSheet("font-size: 12px; color: #aaa;")
        glove_status_layout.addWidget(self.right_hand_info, 1, 2, 1, 2)  # 跨两列
        
        # 添加即将报警计数显示
        self.accumulated_label = QLabel("即将报警计数:")
        self.accumulated_label.setStyleSheet("font-size: 14px; color: #ffcc00;")
        glove_status_layout.addWidget(self.accumulated_label, 2, 0)

        self.accumulated_value = QLabel("0")
        self.accumulated_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #ffcc00;")
        glove_status_layout.addWidget(self.accumulated_value, 2, 1)

        # 添加报警状态显示
        self.alarm_status_label = QLabel("报警状态:")
        self.alarm_status_label.setStyleSheet("font-size: 14px; color: #ffcc00;")
        glove_status_layout.addWidget(self.alarm_status_label, 2, 2)
        
        self.alarm_status_value = QLabel("未激活")
        self.alarm_status_value.setStyleSheet("font-size: 16px; font-weight: bold;")
        glove_status_layout.addWidget(self.alarm_status_value, 2, 3)

        # 添加人员检测状态
        self.person_status_label = QLabel("人员检测:")
        self.person_status_label.setStyleSheet("font-size: 14px; color: #ffcc00;")
        glove_status_layout.addWidget(self.person_status_label, 3, 0)
        
        self.person_status_value = QLabel("未检测")
        self.person_status_value.setStyleSheet("font-size: 16px; font-weight: bold;")
        glove_status_layout.addWidget(self.person_status_value, 3, 1)
        
        # 添加无人计数状态
        self.no_person_count_label = QLabel("无人计数:")
        self.no_person_count_label.setStyleSheet("font-size: 14px; color: #ffcc00;")
        glove_status_layout.addWidget(self.no_person_count_label, 3, 2)
        
        self.no_person_count_value = QLabel("0")
        self.no_person_count_value.setStyleSheet("font-size: 16px; font-weight: bold;")
        glove_status_layout.addWidget(self.no_person_count_value, 3, 3)
        
        # 添加人员检测置信度
        self.person_confidence_label = QLabel("人员置信度:")
        self.person_confidence_label.setStyleSheet("font-size: 14px; color: #ffcc00;")
        glove_status_layout.addWidget(self.person_confidence_label, 4, 0)
        
        self.person_confidence_value = QLabel("0.00")
        self.person_confidence_value.setStyleSheet("font-size: 16px; font-weight: bold;")
        glove_status_layout.addWidget(self.person_confidence_value, 4, 1)

        right_panel.addWidget(self.last_detection_label)
        right_panel.addWidget(self.last_detection_frame)
        right_panel.addWidget(self.glove_status_frame)
        video_display_layout.addLayout(right_panel, 60)
        video_layout.addLayout(video_display_layout)

        # 状态信息
        self.status_label = QLabel("状态: 未连接")
        self.status_label.setFont(QFont("Arial", 10))
        self.status_label.setStyleSheet("color: #aaa;")
        video_layout.addWidget(self.status_label)

        # 消息框
        self.log_group = QGroupBox("系统消息")
        log_layout = QVBoxLayout()
        self.message_box = QTextEdit()
        self.message_box.setReadOnly(True)
        self.message_box.setMinimumHeight(100)
        self.message_box.setStyleSheet("background-color: #f9f9f9; font-size: 12px;")
        log_layout.addWidget(self.message_box)
        self.log_group.setLayout(log_layout)
        video_layout.addWidget(self.log_group)
        
        main_layout.addWidget(self.video_frame, 70)
        
        # 右侧控制区域
        self.control_frame = QFrame()
        self.control_frame.setFrameShape(QFrame.StyledPanel)
        self.control_layout = QVBoxLayout(self.control_frame)
        self.control_layout.setSpacing(8)
        self.control_layout.setContentsMargins(10, 10, 10, 10)
        
        self.tab_widget = QTabWidget()
        self.control_layout.addWidget(self.tab_widget)
        
        # 摄像头控制标签页
        self.cam_tab = QWidget()
        self.init_camera_tab()
        self.tab_widget.addTab(self.cam_tab, "摄像头控制")
        
        # 手套检测标签页
        self.glove_tab = QWidget()
        self.init_glove_tab()
        self.tab_widget.addTab(self.glove_tab, "手套检测设置")
        
        main_layout.addWidget(self.control_frame, 30)
        
        # 状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("就绪")
        self.status_bar.setStyleSheet("background-color: #252526; color: #d4d4d4;")
    
    def init_camera_tab(self):
        layout = QVBoxLayout(self.cam_tab)
        layout.setSpacing(10)
        
        # 暂停识别复选框
        self.pause_recognition_checkbox = QCheckBox("暂停手部识别")
        self.pause_recognition_checkbox.setChecked(self.glove_detector.pause_recognition)
        self.pause_recognition_checkbox.stateChanged.connect(self.toggle_pause_recognition)
        layout.addWidget(self.pause_recognition_checkbox)
        
        # 暂停画面按钮
        self.pause_video_button = QPushButton("暂停画面")
        self.pause_video_button.setStyleSheet(self.get_button_style("#FF9800", "#F57C00"))
        self.pause_video_button.clicked.connect(self.toggle_pause_video)
        layout.addWidget(self.pause_video_button)
        
        # 调试颜色按钮
        self.debug_button = QPushButton("调试颜色")
        self.debug_button.setStyleSheet(self.get_button_style("#9C27B0", "#7B1FA2"))
        self.debug_button.clicked.connect(self.toggle_debug_mode)
        self.debug_button.setEnabled(False)
        layout.addWidget(self.debug_button)
        
        # 配置表单
        config_group = QGroupBox("摄像头配置")
        config_layout = QFormLayout()
        
        self.ip_input = QLineEdit("192.168.1.13")
        self.username_input = QLineEdit("admin")
        self.password_input = QLineEdit("123456@BYD")
        self.password_input.setEchoMode(QLineEdit.Password)
        
        config_layout.addRow("IP地址:", self.ip_input)
        config_layout.addRow("用户名:", self.username_input)
        config_layout.addRow("密码:", self.password_input)
        config_group.setLayout(config_layout)
        layout.addWidget(config_group)
        
        # 高级设置组
        advanced_group = QGroupBox("高级设置")
        advanced_layout = QFormLayout()
        
        # 分辨率设置
        self.resolution_combo = QComboBox()
        self.resolution_combo.addItems(["640x480", "1280x720", "1920x1080", "自定义"])
        self.resolution_combo.currentIndexChanged.connect(self.update_resolution_ui)

        advanced_layout.addRow("分辨率:", self.resolution_combo)

        self.custom_res_layout = QHBoxLayout()
        self.custom_width = QLineEdit("1280")
        self.custom_width.setValidator(QIntValidator(100, 5000))
        self.custom_width.setEnabled(False)
        self.custom_height = QLineEdit("720")
        self.custom_height.setValidator(QIntValidator(100, 5000))
        self.custom_height.setEnabled(False)
        self.custom_res_layout.addWidget(QLabel("宽:"))
        self.custom_res_layout.addWidget(self.custom_width)
        self.custom_res_layout.addWidget(QLabel("高:"))
        self.custom_res_layout.addWidget(self.custom_height)
        advanced_layout.addRow("自定义分辨率:", self.custom_res_layout)

        # 帧率设置
        self.fps_slider = QSlider(Qt.Horizontal)
        self.fps_slider.setRange(1, 30)
        self.fps_slider.setValue(15)
        self.fps_value = QLabel("15")
        fps_layout = QHBoxLayout()
        fps_layout.addWidget(self.fps_slider)
        fps_layout.addWidget(self.fps_value)
        advanced_layout.addRow("帧率 (FPS):", fps_layout)
        self.fps_slider.valueChanged.connect(lambda value: self.fps_value.setText(str(value)))
        
        advanced_group.setLayout(advanced_layout)
        layout.addWidget(advanced_group)
        
        # 状态标签
        self.connection_label = QLabel("连接状态: 未连接")
        self.connection_label.setStyleSheet("color: #ff6b6b;")
        layout.addWidget(self.connection_label)
        
        self.stream_label = QLabel("流状态: 停止")
        self.stream_label.setStyleSheet("color: #ff6b6b;")
        layout.addWidget(self.stream_label)
        
        # 控制按钮
        self.connect_btn = QPushButton("连接摄像头")
        self.connect_btn.clicked.connect(self.toggle_connection)
        self.connect_btn.setStyleSheet(self.get_button_style("#4CAF50", "#45a049"))
        layout.addWidget(self.connect_btn)
        
        self.stream_btn = QPushButton("启动视频流")
        self.stream_btn.clicked.connect(self.toggle_stream)
        self.stream_btn.setEnabled(False)
        self.stream_btn.setStyleSheet(self.get_button_style("#2196F3", "#0b7dda"))
        layout.addWidget(self.stream_btn)
        
        # 手动录制按钮
        self.manual_record_btn = QPushButton("开始手动录制")
        self.manual_record_btn.setStyleSheet(self.get_button_style("#FF5722", "#E64A19"))
        self.manual_record_btn.clicked.connect(self.toggle_manual_recording)
        self.manual_record_btn.setEnabled(False)
        layout.addWidget(self.manual_record_btn)
        
        # PTZ控制
        ptz_group = QGroupBox("PTZ控制")
        ptz_layout = QVBoxLayout()
        
        zoom_group = QGroupBox("镜头缩放")
        zoom_layout = QHBoxLayout()
        self.zoom_in_btn = QPushButton("放大")
        self.zoom_in_btn.setStyleSheet(self.get_button_style("#9C27B0", "#7B1FA2"))
        self.zoom_out_btn = QPushButton("缩小")
        self.zoom_out_btn.setStyleSheet(self.get_button_style("#9C27B0", "#7B1FA2"))
        zoom_layout.addWidget(self.zoom_in_btn)
        zoom_layout.addWidget(self.zoom_out_btn)
        zoom_group.setLayout(zoom_layout)
        
        focus_group = QGroupBox("焦距调整")
        focus_layout = QHBoxLayout()
        self.focus_in_btn = QPushButton("增大焦距")
        self.focus_in_btn.setStyleSheet(self.get_button_style("#FF9800", "#F57C00"))
        self.focus_out_btn = QPushButton("减小焦距")
        self.focus_out_btn.setStyleSheet(self.get_button_style("#FF9800", "#F57C00"))
        focus_layout.addWidget(self.focus_in_btn)
        focus_layout.addWidget(self.focus_out_btn)
        focus_group.setLayout(focus_layout)
        
        ptz_layout.addWidget(zoom_group)
        ptz_layout.addWidget(focus_group)
        ptz_group.setLayout(ptz_layout)
        layout.addWidget(ptz_group)
        
        # 连接PTZ按钮信号
        self.zoom_in_btn.pressed.connect(lambda: self.start_ptz_action('zoom_in'))
        self.zoom_in_btn.released.connect(lambda: self.stop_ptz_action('zoom_in'))
        self.zoom_out_btn.pressed.connect(lambda: self.start_ptz_action('zoom_out'))
        self.zoom_out_btn.released.connect(lambda: self.stop_ptz_action('zoom_out'))
        self.focus_in_btn.pressed.connect(lambda: self.start_ptz_action('focus_in'))
        self.focus_in_btn.released.connect(lambda: self.stop_ptz_action('focus_in'))
        self.focus_out_btn.pressed.connect(lambda: self.start_ptz_action('focus_out'))
        self.focus_out_btn.released.connect(lambda: self.stop_ptz_action('focus_out'))
        
        layout.addStretch(1)
    
    def init_glove_tab(self):
        layout = QVBoxLayout(self.glove_tab)
        layout.setSpacing(10)

        # HSV颜色调节工具
        hsv_group = QGroupBox("HSV颜色调节")
        hsv_layout = QVBoxLayout()
        
        # H范围调节
        h_layout = QVBoxLayout()
        h_label = QLabel("H (色调) 范围:")
        h_layout.addWidget(h_label)
        
        h_min_layout = QHBoxLayout()
        h_min_label = QLabel("最小值:")
        self.h_min_slider = QSlider(Qt.Horizontal)
        self.h_min_slider.setRange(0, 180)
        self.h_min_slider.setValue(self.glove_detector.h_min)
        self.h_min_slider.valueChanged.connect(self.update_hsv_range)
        self.h_min_value = QLabel(str(self.glove_detector.h_min))
        h_min_layout.addWidget(h_min_label)
        h_min_layout.addWidget(self.h_min_slider)
        h_min_layout.addWidget(self.h_min_value)
        h_layout.addLayout(h_min_layout)
        
        h_max_layout = QHBoxLayout()
        h_max_label = QLabel("最大值:")
        self.h_max_slider = QSlider(Qt.Horizontal)
        self.h_max_slider.setRange(0, 180)
        self.h_max_slider.setValue(self.glove_detector.h_max)
        self.h_max_slider.valueChanged.connect(self.update_hsv_range)
        self.h_max_value = QLabel(str(self.glove_detector.h_max))
        h_max_layout.addWidget(h_max_label)
        h_max_layout.addWidget(self.h_max_slider)
        h_max_layout.addWidget(self.h_max_value)
        h_layout.addLayout(h_max_layout)
        
        hsv_layout.addLayout(h_layout)
        
        # S范围调节
        s_layout = QVBoxLayout()
        s_label = QLabel("S (饱和度) 范围:")
        s_layout.addWidget(s_label)
        
        s_min_layout = QHBoxLayout()
        s_min_label = QLabel("最小值:")
        self.s_min_slider = QSlider(Qt.Horizontal)
        self.s_min_slider.setRange(0, 255)
        self.s_min_slider.setValue(self.glove_detector.s_min)
        self.s_min_slider.valueChanged.connect(self.update_hsv_range)
        self.s_min_value = QLabel(str(self.glove_detector.s_min))
        s_min_layout.addWidget(s_min_label)
        s_min_layout.addWidget(self.s_min_slider)
        s_min_layout.addWidget(self.s_min_value)
        s_layout.addLayout(s_min_layout)
        
        s_max_layout = QHBoxLayout()
        s_max_label = QLabel("最大值:")
        self.s_max_slider = QSlider(Qt.Horizontal)
        self.s_max_slider.setRange(0, 255)
        self.s_max_slider.setValue(self.glove_detector.s_max)
        self.s_max_slider.valueChanged.connect(self.update_hsv_range)
        self.s_max_value = QLabel(str(self.glove_detector.s_max))
        s_max_layout.addWidget(s_max_label)
        s_max_layout.addWidget(self.s_max_slider)
        s_max_layout.addWidget(self.s_max_value)
        s_layout.addLayout(s_max_layout)
        
        hsv_layout.addLayout(s_layout)
        
        # V范围调节
        v_layout = QVBoxLayout()
        v_label = QLabel("V (亮度) 范围:")
        v_layout.addWidget(v_label)
        
        v_min_layout = QHBoxLayout()
        v_min_label = QLabel("最小值:")
        self.v_min_slider = QSlider(Qt.Horizontal)
        self.v_min_slider.setRange(0, 255)
        self.v_min_slider.setValue(self.glove_detector.v_min)
        self.v_min_slider.valueChanged.connect(self.update_hsv_range)
        self.v_min_value = QLabel(str(self.glove_detector.v_min))
        v_min_layout.addWidget(v_min_label)
        v_min_layout.addWidget(self.v_min_slider)
        v_min_layout.addWidget(self.v_min_value)
        v_layout.addLayout(v_min_layout)
        
        v_max_layout = QHBoxLayout()
        v_max_label = QLabel("最大值:")
        self.v_max_slider = QSlider(Qt.Horizontal)
        self.v_max_slider.setRange(0, 255)
        self.v_max_slider.setValue(self.glove_detector.v_max)
        self.v_max_slider.valueChanged.connect(self.update_hsv_range)
        self.v_max_value = QLabel(str(self.glove_detector.v_max))
        v_max_layout.addWidget(v_max_label)
        v_max_layout.addWidget(self.v_max_slider)
        v_max_layout.addWidget(self.v_max_value)
        v_layout.addLayout(v_max_layout)
        
        hsv_layout.addLayout(v_layout)
        
        # 颜色容差控制
        tolerance_layout = QHBoxLayout()
        tolerance_label = QLabel("颜色容差:")
        self.tolerance_slider = QSlider(Qt.Horizontal)
        self.tolerance_slider.setMinimum(10)
        self.tolerance_slider.setMaximum(60)
        self.tolerance_slider.setValue(self.glove_detector.color_tolerance)
        self.tolerance_slider.valueChanged.connect(self.update_color_tolerance)
        self.tolerance_value = QLabel(str(self.glove_detector.color_tolerance))
        tolerance_layout.addWidget(tolerance_label)
        tolerance_layout.addWidget(self.tolerance_slider)
        tolerance_layout.addWidget(self.tolerance_value)
        hsv_layout.addLayout(tolerance_layout)
        
        hsv_group.setLayout(hsv_layout)
        layout.addWidget(hsv_group)

        # 点采样参数
        point_group = QGroupBox("点采样参数")
        point_layout = QGridLayout()
        
        # 点数量阈值
        point_layout.addWidget(QLabel("点数量阈值:"), 0, 0)
        self.point_threshold_slider = QSlider(Qt.Horizontal)
        self.point_threshold_slider.setRange(1, 500)
        self.point_threshold_slider.setValue(self.glove_detector.point_threshold)
        self.point_threshold_slider.valueChanged.connect(self.update_point_threshold)
        point_layout.addWidget(self.point_threshold_slider, 0, 1)
        self.point_threshold_value = QLabel(str(self.glove_detector.point_threshold))
        point_layout.addWidget(self.point_threshold_value, 0, 2)
        
        # 比例阈值
        point_layout.addWidget(QLabel("比例阈值:"), 1, 0)
        self.ratio_threshold_slider = QSlider(Qt.Horizontal)
        self.ratio_threshold_slider.setRange(1, 100)
        self.ratio_threshold_slider.setValue(int(self.glove_detector.ratio_threshold * 100))
        self.ratio_threshold_slider.valueChanged.connect(self.update_ratio_threshold)
        point_layout.addWidget(self.ratio_threshold_slider, 1, 1)
        self.ratio_threshold_value = QLabel(f"{self.glove_detector.ratio_threshold:.2f}")
        point_layout.addWidget(self.ratio_threshold_value, 1, 2)
        point_layout.addWidget(QLabel("全局点采样间隔:"), 2, 0)

        self.global_point_interval_slider = QSlider(Qt.Horizontal)
        self.global_point_interval_slider.setRange(1, 20)
        self.global_point_interval_slider.setValue(self.glove_detector.global_point_interval)
        self.global_point_interval_slider.valueChanged.connect(self.update_global_point_interval)
        point_layout.addWidget(self.global_point_interval_slider, 2, 1)
        self.global_point_interval_value = QLabel(str(self.glove_detector.global_point_interval))
        point_layout.addWidget(self.global_point_interval_value, 2, 2)

        point_group.setLayout(point_layout)
        layout.addWidget(point_group)
        
        # 检测帧率控制
        frame_rate_group = QGroupBox("检测帧率")
        frame_rate_layout = QGridLayout()
        frame_rate_layout.addWidget(QLabel("检测间隔(毫秒):"), 0, 0)
        
        self.detection_interval_slider = QSlider(Qt.Horizontal)
        self.detection_interval_slider.setRange(100, 1000)
        self.detection_interval_slider.setValue(self.glove_detector.detection_interval)
        self.detection_interval_slider.valueChanged.connect(self.update_detection_interval)
        frame_rate_layout.addWidget(self.detection_interval_slider, 0, 1)
        
        self.detection_interval_value = QLabel(f"{self.glove_detector.detection_interval}ms")
        frame_rate_layout.addWidget(self.detection_interval_value, 0, 2)
        frame_rate_group.setLayout(frame_rate_layout)
        layout.addWidget(frame_rate_group)
        
        # 其他参数
        param_group = QGroupBox("检测参数")
        param_layout = QVBoxLayout()
        
        # 置信度阈值
        confidence_layout = QHBoxLayout()
        confidence_layout.addWidget(QLabel("手部置信度阈值:"))
        self.confidence_slider = QSlider(Qt.Horizontal)
        self.confidence_slider.setRange(10, 90)
        self.confidence_slider.setValue(int(self.glove_detector.hand_confidence_threshold * 100))
        self.confidence_slider.valueChanged.connect(self.update_confidence_threshold)
        confidence_layout.addWidget(self.confidence_slider)
        self.confidence_value = QLabel(f"{self.glove_detector.hand_confidence_threshold:.2f}")
        confidence_layout.addWidget(self.confidence_value)
        param_layout.addLayout(confidence_layout)

        # 手腕半径控制 (新增)
        wrist_layout = QHBoxLayout()
        wrist_layout.addWidget(QLabel("手腕区域半径:"))
        self.wrist_radius_slider = QSlider(Qt.Horizontal)
        self.wrist_radius_slider.setRange(10, 100)
        self.wrist_radius_slider.setValue(self.glove_detector.wrist_radius)
        self.wrist_radius_slider.valueChanged.connect(self.update_wrist_radius)
        wrist_layout.addWidget(self.wrist_radius_slider)
        self.wrist_radius_value = QLabel(str(self.glove_detector.wrist_radius))
        wrist_layout.addWidget(self.wrist_radius_value)
        param_layout.addLayout(wrist_layout)
        
        param_group.setLayout(param_layout)
        layout.addWidget(param_group)

        # 报警设置
        alarm_group = QGroupBox("报警设置")
        alarm_layout = QVBoxLayout()
        self.alarm_checkbox = QCheckBox("启用未佩戴手套报警")
        self.alarm_checkbox.setChecked(True)
        alarm_layout.addWidget(self.alarm_checkbox)
        
        self.max_misses_label = QLabel("最大允许未检测次数:")
        self.max_misses_input = QLineEdit(str(self.glove_detector.max_missed_detections))
        self.max_misses_input.setValidator(QIntValidator(1, 100))
        alarm_layout.addWidget(self.max_misses_label)
        alarm_layout.addWidget(self.max_misses_input)
        
        alarm_group.setLayout(alarm_layout)
        layout.addWidget(alarm_group)
        
        # 保存按钮
        self.save_params_button = QPushButton("保存参数")
        self.save_params_button.setMinimumHeight(30)
        self.save_params_button.clicked.connect(self.save_glove_parameters)
        layout.addWidget(self.save_params_button)
        
        layout.addStretch(1)
    
    def update_wrist_radius(self, value):
        """更新手腕半径设置"""
        self.glove_detector.wrist_radius = value
        self.wrist_radius_value.setText(str(value))
        self.add_message("手腕半径", f"手腕区域半径设置为: {value}像素")

    def update_resolution_ui(self, index):
        """更新分辨率UI状态"""
        is_custom = (index == 3)  # 自定义选项
        self.custom_width.setEnabled(is_custom)
        self.custom_height.setEnabled(is_custom)
        
        if not is_custom:
            # 设置预定义分辨率
            resolutions = {
                0: (640, 480),
                1: (1280, 720),
                2: (1920, 1080)
            }
            if index in resolutions:
                width, height = resolutions[index]
                self.custom_width.setText(str(width))
                self.custom_height.setText(str(height))
    
    def update_global_point_interval(self, value):
        self.glove_detector.global_point_interval = value
        self.global_point_interval_value.setText(str(value))
        self.add_message("点采样设置", f"全局点采样间隔设置为: {value}")

    def set_dark_theme(self):
        dark_palette = QPalette()
        dark_palette.setColor(QPalette.Window, QColor(37, 37, 38))
        dark_palette.setColor(QPalette.WindowText, QColor(212, 212, 212))
        dark_palette.setColor(QPalette.Base, QColor(30, 30, 30))
        dark_palette.setColor(QPalette.ToolTipBase, QColor(37, 37, 38))
        dark_palette.setColor(QPalette.ToolTipText, QColor(212, 212, 212))
        dark_palette.setColor(QPalette.Text, QColor(212, 212, 212))
        dark_palette.setColor(QPalette.Button, QColor(45, 45, 48))
        dark_palette.setColor(QPalette.ButtonText, QColor(212, 212, 212))
        dark_palette.setColor(QPalette.Link, QColor(86, 156, 214))
        dark_palette.setColor(QPalette.Highlight, QColor(86, 156, 214))
        self.setPalette(dark_palette)
        
        self.setStyleSheet("""
            QGroupBox {
                border: 1px solid #444;
                border-radius: 5px;
                margin-top: 1ex;
                font-weight: bold;
                color: #d4d4d4;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 3px 0 3px;
            }
            QLabel {
                color: #d4d4d4;
            }
            QLineEdit {
                background-color: #252526;
                color: #d4d4d4;
                border: 1px solid #444;
                padding: 5px;
                border-radius: 3px;
            }
            QTabWidget::pane {
                border: 1px solid #444;
                top: 1px;
            }
            QTabBar::tab {
                background: #2d2d30;
                border: 1px solid #444;
                padding: 5px 10px;
            }
            QTabBar::tab:selected {
                background: #3e3e42;
                border-bottom: 2px solid #007acc;
            }
        """)
    
    def get_button_style(self, normal_color, hover_color):
        return f"""
            QPushButton {{
                background-color: {normal_color}; 
                color: white;
                padding: 8px;
                border-radius: 4px;
                font-weight: bold;
                min-width: 80px;
            }}
            QPushButton:hover {{
                background-color: {hover_color};
            }}
            QPushButton:disabled {{
                background-color: #555;
            }}
        """
    
    def update_frame(self, frame):
        """接收原始视频帧并发送到检测线程"""
        if frame is None or frame.size == 0:
            return
            
        # 保存当前帧
        self.current_frame = frame
        self.paused_frame = frame
        
        # 录制当前帧
        self.glove_detector.record_frame(frame)
        
        # 调试模式特殊处理
        if self.debug_mode:
            self.update_debug_display()
            return
            
        # 发送到检测线程
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.add_frame(frame)
        
        # 显示原始帧
        self.display_frame(frame, self.raw_video_label)
    
    def display_frame(self, frame, label):
        """在指定标签上显示帧"""
        if frame is None or frame.size == 0:
            return
        # 优化：使用固定尺寸显示，减少计算量
        target_width = 640
        target_height = 360
        
        # 检查是否需要调整尺寸
        if frame.shape[1] != target_width or frame.shape[0] != target_height:
            resized_frame = cv2.resize(frame, (target_width, target_height))
        else:
            resized_frame = frame

        rgb_frame = cv2.cvtColor(resized_frame, cv2.COLOR_BGR2RGB)
        h, w, ch = rgb_frame.shape
        bytes_per_line = ch * w
        qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
        
        if qt_image.isNull():
            return
            
        pixmap = QPixmap.fromImage(qt_image)
        scaled_pixmap = pixmap.scaled(
            label.size(), 
            Qt.KeepAspectRatio, 
            Qt.SmoothTransformation
        )
        label.setPixmap(scaled_pixmap)
    
    def update_detection_result(self, raw_frame, processed_frame, left_detected, right_detected, left_info, right_info, missed_count, person_detected, person_confidence):
        """接收检测线程的处理结果并更新UI"""
        # 在调试模式下，不更新检测结果
        if self.glove_detector.debug_mode:
            return
            
        # 更新检测帧显示
        if processed_frame is not None:
            self.display_frame(processed_frame, self.last_detection_frame)
        
        # 更新手套状态
        left_status = "已佩戴" if left_detected else "未佩戴"
        left_color = "#ccffcc" if left_detected else "#ffcccc"
        self.left_hand_result.setText(f"左手: {left_status}")
        self.left_hand_result.setStyleSheet(f"font-size: 16px; font-weight: bold; background-color: {left_color};")
        
        # 更新左手详细信息 - 添加阈值对比信息
        if left_info:
            method = left_info.get('method', '未知')
            points = left_info.get('points', 0)
            ratio = left_info.get('ratio', 0.0)
            # 添加阈值对比信息
            threshold_info = f"点阈值: {self.glove_detector.point_threshold}/{points}"
            ratio_info = f"占比阈值: {self.glove_detector.ratio_threshold:.2f}/{ratio:.2f}"
            self.left_hand_info.setText(f"{method} | {threshold_info} | {ratio_info}")
        else:
            self.left_hand_info.setText("无信息")
        
        right_status = "已佩戴" if right_detected else "未佩戴"
        right_color = "#ccffcc" if right_detected else "#ffcccc"
        self.right_hand_result.setText(f"右手: {right_status}")
        self.right_hand_result.setStyleSheet(f"font-size: 16px; font-weight: bold; background-color: {right_color};")
        
        # 更新右手详细信息 - 添加阈值对比信息
        if right_info:
            method = right_info.get('method', '未知')
            points = right_info.get('points', 0)
            ratio = right_info.get('ratio', 0.0)
            # 添加阈值对比信息
            threshold_info = f"点阈值: {self.glove_detector.point_threshold}/{points}"
            ratio_info = f"占比阈值: {self.glove_detector.ratio_threshold:.2f}/{ratio:.2f}"
            self.right_hand_info.setText(f"{method} | {threshold_info} | {ratio_info}")
        else:
            self.right_hand_info.setText("无信息")
            
        # 更新累加数据
        self.accumulated_value.setText(str(missed_count))
        
        # 根据计数设置不同颜色
        if missed_count >= self.glove_detector.max_missed_detections - 1:  # 接近阈值
            self.accumulated_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #ff0000;")  # 红色
        elif missed_count > 0:
            self.accumulated_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #ffcc00;")  # 黄色
        else:
            self.accumulated_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #00ff00;")  # 绿色
        
        # 更新报警状态显示
        alarm_status = "激活" if self.glove_detector.alarm_active else "未激活"
        alarm_color = "#ff0000" if self.glove_detector.alarm_active else "#00ff00"
        self.alarm_status_value.setText(alarm_status)
        self.alarm_status_value.setStyleSheet(f"font-size: 16px; font-weight: bold; color: {alarm_color};")
        
        # 更新人员检测状态
        person_status = "检测到人" if person_detected else "未检测到人"
        person_color = "#00ff00" if person_detected else "#ff0000"
        self.person_status_value.setText(person_status)
        self.person_status_value.setStyleSheet(f"font-size: 16px; font-weight: bold; color: {person_color};")
        
        # 更新无人计数
        self.no_person_count_value.setText(str(self.glove_detector.no_person_count))
        if self.glove_detector.no_person_count > 0:
            self.no_person_count_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #ffcc00;")
        else:
            self.no_person_count_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #00ff00;")
            
        # 更新人员检测置信度
        self.person_confidence_value.setText(f"{person_confidence:.2f}")
        if person_confidence > 0.5:
            self.person_confidence_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #00ff00;")
        elif person_confidence > 0.3:
            self.person_confidence_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #ffcc00;")
        else:
            self.person_confidence_value.setStyleSheet("font-size: 16px; font-weight: bold; color: #ff0000;")
    
    def update_status(self, status):
        self.status_label.setText(f"状态: {status}")
    
    def start_ptz_action(self, action):
        self.ptz_timers[action].start()
        self.send_ptz_command(action, True)
 
    def stop_ptz_action(self, action):
        self.ptz_timers[action].stop()
        self.send_ptz_command(action, False)
 
    def send_continuous_ptz(self, action):
        self.send_ptz_command(action, True)
    
    def toggle_connection(self):
        if self.video_thread and self.video_thread.isRunning():
            self.disconnect_camera()
        else:
            self.connect_camera()
    
    def toggle_stream(self):
        if self.video_thread and self.video_thread.isRunning():
            self.stop_stream()
        else:
            self.start_stream()
    
    def toggle_manual_recording(self):
        if self.glove_detector.manual_recording:
            if self.glove_detector.stop_manual_recording():
                self.manual_record_btn.setText("开始手动录制")
                self.manual_record_btn.setStyleSheet(self.get_button_style("#FF5722", "#E64A19"))
        else:
            if not self.video_thread or not self.video_thread.isRunning():
                self.status_bar.showMessage("请先启动视频流")
                return
                
            if self.glove_detector.start_manual_recording():
                self.manual_record_btn.setText("停止手动录制")
                self.manual_record_btn.setStyleSheet(self.get_button_style("#f44336", "#d32f2f"))

    def connect_camera(self):
        ip = self.ip_input.text().strip()
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()
        
        if not ip:
            self.status_bar.showMessage("请输入摄像头IP地址")
            return
            
        # 获取分辨率设置
        try:
            self.video_width = int(self.custom_width.text())
            self.video_height = int(self.custom_height.text())
            self.video_fps = self.fps_slider.value()
        except ValueError:
            self.video_width = 1280
            self.video_height = 720
            self.video_fps = 15
            
        rtsp_url = f"rtsp://{username}:{password}@{ip}:554/streaming/channels/1"
        self.status_bar.showMessage("正在连接摄像头...")
        
        if self.start_stream(rtsp_url):
            self.connect_btn.setText("断开连接")
            self.connect_btn.setStyleSheet(self.get_button_style("#f44336", "#d32f2f"))
            self.stream_btn.setEnabled(True)
            self.connection_label.setText("连接状态: 已连接")
            self.connection_label.setStyleSheet("color: #4caf50;")
            self.status_label.setText("状态: 已连接")
            self.status_bar.showMessage("摄像头已连接")
            self.manual_record_btn.setEnabled(True)
            
            # 创建检测线程
            if not self.detection_thread or not self.detection_thread.isRunning():
                self.detection_thread = DetectionThread(self.glove_detector)
                self.detection_thread.result_signal.connect(
                    lambda rf, pf, ld, rd, li, ri, mc, pd, pc: 
                    self.update_detection_result(rf, pf, ld, rd, li, ri, mc, pd, pc))
                self.detection_thread.debug_signal.connect(self.add_message)  # 连接调试信号
                self.detection_thread.start()
        else:
            self.status_bar.showMessage("摄像头连接失败")
    
    def disconnect_camera(self):
        if self.video_thread and self.video_thread.isRunning():
            self.stop_stream()
            
        self.connect_btn.setText("连接摄像头")
        self.connect_btn.setStyleSheet(self.get_button_style("#4CAF50", "#45a049"))
        self.stream_btn.setEnabled(False)
        self.stream_btn.setText("启动视频流")
        self.stream_btn.setStyleSheet(self.get_button_style("#2196F3", "#0b7dda"))
        self.connection_label.setText("连接状态: 未连接")
        self.connection_label.setStyleSheet("color: #ff6b6b;")
        self.stream_label.setText("流状态: 停止")
        self.stream_label.setStyleSheet("color: #ff6b6b;")
        self.status_label.setText("状态: 未连接")
        self.status_bar.showMessage("摄像头已断开")
        self.manual_record_btn.setEnabled(False)
        
        # 停止检测线程
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.stop()
            self.detection_thread = None
    
    def start_stream(self, rtsp_url=None):
        self.status_bar.showMessage("正在启动视频流...")
        
        if rtsp_url is None:
            ip = self.ip_input.text().strip()
            username = self.username_input.text().strip()
            password = self.password_input.text().strip()
            rtsp_url = f"rtsp://{username}:{password}@{ip}:554/streaming/channels/1"
        
        try:
            # 停止现有的视频线程
            if self.video_thread and self.video_thread.isRunning():
                self.video_thread.stop()
            
            self.video_thread = VideoThread(rtsp_url, self.video_width, self.video_height, self.video_fps)
            self.video_thread.frame_signal.connect(self.update_frame)
            self.video_thread.status_signal.connect(self.update_status)
            self.video_thread.start()
            
            self.stream_btn.setText("停止视频流")
            self.stream_btn.setStyleSheet(self.get_button_style("#f44336", "#d32f2f"))
            self.stream_label.setText("流状态: 运行中")
            self.stream_label.setStyleSheet("color: #4caf50;")
            self.status_label.setText("状态: 流运行中")
            self.status_bar.showMessage("视频流已启动")
            
            return True
            
        except Exception as e:
            self.status_bar.showMessage(f"启动视频流失败: {str(e)}")
            return False
    
    def stop_stream(self):
        self.status_bar.showMessage("正在停止视频流...")
        
        if self.video_thread and self.video_thread.isRunning():
            self.video_thread.stop()
            self.video_thread.wait(2000)
        
        self.stream_btn.setText("启动视频流")
        self.stream_btn.setStyleSheet(self.get_button_style("#2196F3", "#0b7dda"))
        self.stream_label.setText("流状态: 停止")
        self.stream_label.setStyleSheet("color: #ff6b6b;")
        self.status_label.setText("状态: 已连接，流停止")
        self.status_bar.showMessage("视频流已停止")
    
    def send_ptz_command(self, action, is_start):
        ip = self.ip_input.text().strip()
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()
        
        if not ip:
            self.status_bar.showMessage("请输入摄像头IP地址")
            return
        
        # 修正PTZ命令映射
        command_map = {
            'zoom_in': {"start": 770, "stop": 769},
            'zoom_out': {"start": 772, "stop": 771},
            'focus_in': {"start": 516, "stop": 515},
            'focus_out': {"start": 514, "stop": 513}
        }
        
        command_names = {
            'zoom_in': "放大",
            'zoom_out': "缩小",
            'focus_in': "增大焦距",
            'focus_out': "减小焦距"
        }
        
        if action not in command_map:
            self.status_bar.showMessage(f"无效的PTZ操作: {action}")
            return
            
        command_type = "start" if is_start else "stop"
        ptz_cmd = command_map[action][command_type]
        
        url = f"http://{ip}/LAPI/V1.0/Channel/0/PTZ/PTZCtrl"
        data = {
            "PTZCmd": ptz_cmd,
            "ContinueTime": 0,
            "Para1": 0,
            "Para2": 0,
            "Para3": 0
        }
        
        action_type = "开始" if is_start else "停止"
        action_name = command_names.get(action, action)
        status_message = f"PTZ命令: {action_type} {action_name} (代码: {ptz_cmd})"
        
        try:
            response = requests.put(
                url,
                auth=HTTPDigestAuth(username, password),
                json=data,
                headers={"Content-Type": "application/json"},
                timeout=5
            )
            
            if response.status_code == 200:
                try:
                    resp_json = response.json()
                    response_code = resp_json.get("Response", {}).get("ResponseCode", -1)
                    if response_code == 0:
                        self.status_bar.showMessage(f"成功: {status_message}")
                    else:
                        error_msg = resp_json.get("Response", {}).get("ResponseString", "未知错误")
                        self.status_bar.showMessage(f"API错误: {error_msg} (代码: {response_code})")
                except ValueError:
                    self.status_bar.showMessage(f"成功(未解析响应): {status_message}")
            else:
                try:
                    error_details = response.json()
                    self.status_bar.showMessage(f"请求失败({response.status_code}): {error_details}")
                except:
                    self.status_bar.showMessage(f"请求失败，状态码: {response.status_code}")
        except Exception as e:
            self.status_bar.showMessage(f"命令发送错误: {str(e)}")
    
    def update_detection_interval(self, value):
        self.glove_detector.detection_interval = value
        self.detection_interval_value.setText(f"{value}ms")
        self.add_message("检测设置", f"检测间隔设置为: {value}ms")
    
    def update_hsv_range(self):
        self.glove_detector.h_min = self.h_min_slider.value()
        self.glove_detector.h_max = self.h_max_slider.value()
        self.glove_detector.s_min = self.s_min_slider.value()
        self.glove_detector.s_max = self.s_max_slider.value()
        self.glove_detector.v_min = self.v_min_slider.value()
        self.glove_detector.v_max = self.v_max_slider.value()
        
        self.h_min_value.setText(str(self.glove_detector.h_min))
        self.h_max_value.setText(str(self.glove_detector.h_max))
        self.s_min_value.setText(str(self.glove_detector.s_min))
        self.s_max_value.setText(str(self.glove_detector.s_max))
        self.v_min_value.setText(str(self.glove_detector.v_min))
        self.v_max_value.setText(str(self.glove_detector.v_max))
        
        self.add_message("HSV设置", f"H:[{self.glove_detector.h_min}-{self.glove_detector.h_max}], S:[{self.glove_detector.s_min}-{self.glove_detector.s_max}], V:[{self.glove_detector.v_min}-{self.glove_detector.v_max}]")
        
        # 在调试模式下强制更新显示
        if self.debug_mode and self.paused_frame is not None:
            self.update_debug_display()
    
    def update_color_tolerance(self, value):
        self.glove_detector.color_tolerance = value
        self.tolerance_value.setText(str(value))
        self.add_message("颜色容差", f"颜色容差设置为: {value}")
        
        # 在调试模式下强制更新显示
        if self.debug_mode and self.paused_frame is not None:
            self.update_debug_display()
    
    def update_point_threshold(self, value):
        self.glove_detector.point_threshold = value
        self.point_threshold_value.setText(str(value))
        self.add_message("点数量阈值", f"白手套点数量阈值设置为: {value}")
    
    def update_ratio_threshold(self, value):
        ratio_value = value / 100.0
        self.glove_detector.ratio_threshold = ratio_value
        self.ratio_threshold_value.setText(f"{ratio_value:.2f}")
        self.add_message("比例阈值", f"白手套点比例阈值设置为: {ratio_value:.2f}")
    
    def update_confidence_threshold(self, value):
        confidence_value = value / 100.0
        self.glove_detector.hand_confidence_threshold = confidence_value
        self.confidence_value.setText(f"{confidence_value:.2f}")
        self.add_message("置信度阈值", f"手部置信度阈值设置为: {confidence_value:.2f}")
    
    def toggle_pause_recognition(self, state):
        self.glove_detector.pause_recognition = state == Qt.Checked
        self.add_message("识别状态", f"手部识别 {'已暂停' if state == Qt.Checked else '已启用'}")
    
    def toggle_pause_video(self):
        """切换视频暂停状态"""
        if self.video_thread and self.video_thread.isRunning():
            self.video_paused = not self.video_paused
            self.video_thread.running = not self.video_paused
            if self.video_paused:
                self.pause_video_button.setText("继续画面")
                self.debug_button.setEnabled(True)
                self.add_message("视频控制", "视频画面已暂停")
            else:
                self.pause_video_button.setText("暂停画面")
                self.debug_button.setEnabled(False)
                self.add_message("视频控制", "视频画面已继续")
    
    def toggle_debug_mode(self):
        """切换调试模式"""
        self.debug_mode = not self.debug_mode
        self.glove_detector.debug_mode = self.debug_mode
        
        if self.debug_mode:
            self.debug_button.setText("退出调试")
            self.add_message("调试模式", "已进入调试模式")
            # 保存当前帧用于调试
            if self.paused_frame is not None:
                self.update_debug_display()
        else:
            self.debug_button.setText("调试颜色")
            self.add_message("调试模式", "已退出调试模式")
            # 恢复显示
            if self.paused_frame is not None:
                self.display_frame(self.paused_frame, self.raw_video_label)
                self.display_frame(self.paused_frame, self.last_detection_frame)
    
    def update_debug_display(self):
        """在调试模式下更新显示"""
        if self.paused_frame is None:
            return
            
        # 创建调试帧副本
        debug_frame = self.paused_frame.copy()
        
        # 绘制全局白手套点
        self.glove_detector.draw_global_glove_points(debug_frame)
        
        # 显示在UI上
        self.display_frame(debug_frame, self.raw_video_label)
        self.display_frame(debug_frame, self.last_detection_frame)
    
    def add_message(self, title, content):
        timestamp = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
        message = f"[{timestamp}] {title}: {content}"
        self.message_box.append(message)
        self.message_box.verticalScrollBar().setValue(self.message_box.verticalScrollBar().maximum())
    
    def update_alarm(self):
        if self.glove_detector.alarm_active and self.alarm_checkbox.isChecked():
            elapsed = (datetime.datetime.now() - self.glove_detector.alarm_start_time).total_seconds()
            phase = (elapsed % (self.glove_detector.alarm_duration * 2)) / (self.glove_detector.alarm_duration * 2)
            
            if phase < 0.5:
                self.video_frame.setStyleSheet("background-color: #ff0000; border: 2px solid #ff0000;")
            else:
                self.video_frame.setStyleSheet("background-color: #1e1e1e; border: 1px solid #444;")
        else:
            self.video_frame.setStyleSheet("background-color: #1e1e1e; border: 1px solid #444;")
            
        # 限制报警持续时间
        if self.glove_detector.alarm_active:
            elapsed = (datetime.datetime.now() - self.glove_detector.alarm_start_time).total_seconds()
            if elapsed > self.max_alarm_duration:
                self.glove_detector.alarm_active = False
                self.glove_detector.stop_alarm_sound()
    
    def load_camera_settings(self):
        """加载摄像头设置"""
        try:
            if os.path.exists("camera_settings.json"):
                with open("camera_settings.json", "r") as f:
                    settings = json.load(f)
                    self.ip_input.setText(settings.get("ip", "192.168.1.13"))
                    self.username_input.setText(settings.get("username", "admin"))
                    self.password_input.setText(settings.get("password", "123456@BYD"))
                    self.fps_slider.setValue(settings.get("fps", 15))
                    
                    # 分辨率设置
                    res_index = settings.get("res_index", 1)
                    self.resolution_combo.setCurrentIndex(res_index)
                    self.custom_width.setText(str(settings.get("custom_width", 1280)))
                    self.custom_height.setText(str(settings.get("custom_height", 720)))
                    self.update_resolution_ui(res_index)
        except Exception as e:
            print(f"加载摄像头设置失败: {str(e)}")
    
    def save_camera_settings(self):
        """保存摄像头设置"""
        try:
            settings = {
                "ip": self.ip_input.text(),
                "username": self.username_input.text(),
                "password": self.password_input.text(),
                "fps": self.fps_slider.value(),
                "res_index": self.resolution_combo.currentIndex(),
                "custom_width": self.custom_width.text(),
                "custom_height": self.custom_height.text(),
            }
            
            with open("camera_settings.json", "w") as f:
                json.dump(settings, f, indent=4)
            return True
        except Exception as e:
            print(f"保存摄像头设置失败: {str(e)}")
            return False
    
    def closeEvent(self, event):
        # 停止所有线程
        if self.video_thread and self.video_thread.isRunning():
            self.video_thread.stop()
            self.video_thread.wait(2000)
        
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.stop()
            self.detection_thread.wait(2000)
        
        # 停止录制
        self.glove_detector.stop_manual_recording()
        
        # 停止所有PTZ定时器
        for timer in self.ptz_timers.values():
            timer.stop()
        
        # 保存摄像头设置
        self.save_camera_settings()
        
        super().closeEvent(event)
    
    def save_glove_parameters(self):
        try:
            # 更新参数
            self.glove_detector.params.update({
                "detection_interval": self.glove_detector.detection_interval,
                "pause_recognition": self.pause_recognition_checkbox.isChecked(),
                "hand_confidence_threshold": self.glove_detector.hand_confidence_threshold,
                "max_missed_detections": int(self.max_misses_input.text()),
                "global_point_interval": self.glove_detector.global_point_interval,
                "h_min": self.glove_detector.h_min,
                "h_max": self.glove_detector.h_max,
                "s_min": self.glove_detector.s_min,
                "s_max": self.glove_detector.s_max,
                "v_min": self.glove_detector.v_min,
                "v_max": self.glove_detector.v_max,
                "color_tolerance": self.glove_detector.color_tolerance,
                "point_threshold": self.glove_detector.point_threshold,
                "ratio_threshold": self.glove_detector.ratio_threshold,
                "wrist_radius": self.glove_detector.wrist_radius  # 保存手腕半径
            })
            
            # 保存到文件
            if self.glove_detector.save_parameters():
                self.glove_detector.pause_recognition = self.pause_recognition_checkbox.isChecked()
                self.glove_detector.max_missed_detections = int(self.max_misses_input.text())
                self.add_message("参数设置", "参数已成功保存")
            else:
                self.add_message("参数错误", "保存参数失败")
        except Exception as e:
            self.add_message("参数错误", f"保存参数失败: {str(e)}")
                    
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())